package sqlpaser;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.hadoop.hive.ql.lib.Node;
import org.apache.hadoop.hive.ql.parse.ASTNode;
import org.apache.hadoop.hive.ql.parse.ParseDriver;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static org.apache.hadoop.hive.ql.parse.HiveParser.*;

/**
 * @author admin
 * @date 2019/10/21 13:51
 */
@Slf4j
@Data
public class HiveSqlParser {
    private ParseDriver pd = new ParseDriver();
    private List<String> tables = Lists.newArrayList();

    public HiveSqlParser() {
    }

    public HiveSqlParser(String sql) {
        parse(sql);
    }

    /**
     * sql解析
     *
     * @param sql
     */
    public void parse(String sql) {
        try {
            ASTNode ast = pd.parse(sql);
            log.info("hiveSql={},astTree={}", sql, ast.toStringTree());
            parseNode(ast);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    private void parseNode(ASTNode ast) {
        if (CollectionUtils.isNotEmpty(ast.getChildren())) {
            for (Node child : ast.getChildren()) {
                ASTNode cc = (ASTNode) child;
                switch (cc.getToken().getType()) {
                    case TOK_INSERT:
                        break;
                    case TOK_TABNAME:
                        String tableName = Joiner.on(".")
                                .join(cc.getChildren()
                                        .stream().map(n -> ((ASTNode) n).getText()).collect(Collectors.toList()));
                        tables.add(tableName);
                        break;
                    case TOK_QUERY:
                        break;
                    case TOK_SELECT:
                    case TOK_SELECTDI:
                        break;
                    default:
                }
                parseNode(cc);
            }
        }
    }

    private void insert(ASTNode cn) {
        if (CollectionUtils.isEmpty(cn.getChildren())) {
            return;
        }
        for (Node child : cn.getChildren()) {
            ASTNode cc = (ASTNode) child;
            switch (cc.getToken().getType()) {
                case TOK_INSERT_INTO:
                case TOK_DESTINATION:
                    insertTable(cn);
                    continue;
                case TOK_SELECT:
                default:
            }
            insert(cc);
        }
    }

    private void parseColumns(ASTNode cc, HiveTableParseInfo table) {
        for (Node node : cc.getChildren()) {
            ASTNode tokSelExpr = (ASTNode) node;
            HiveTableParseInfo.HiveTableColumnParseInfo column = new HiveTableParseInfo.HiveTableColumnParseInfo();
            String alias = getSelExprAlias(tokSelExpr);
            column.setName(alias);
            parseColumn(tokSelExpr, column);
            table.getColumns().add(column);
        }
    }


    private void parseColumn(ASTNode tokSelExpr, HiveTableParseInfo.HiveTableColumnParseInfo column) {
        if (CollectionUtils.isEmpty(tokSelExpr.getChildren())) {
            return;
        }
        for (Node child : tokSelExpr.getChildren()) {
            ASTNode cc = (ASTNode) child;
            if (cc.getToken().getType() == TOK_TABLE_OR_COL) {
                ASTNode ccc = (ASTNode) cc.getParent().getChild(cc.getParent().getChildCount() - 1);
                String[] item;
                if (ccc.getToken().getType() == TOK_TABLE_OR_COL) {
                    item = new String[]{cc.getChild(0).getText(), ""};
                } else {
                    item = new String[]{ccc.getText(), cc.getChild(0).getText()};
                }
                Optional<String[]> any = column.getSourceList().stream().filter(s -> Arrays.equals(item, s)).findAny();
                if (!any.isPresent()) {
                    column.getSourceList().add(item);
                }
                continue;
            }
            parseColumn(cc, column);
        }
    }

    /**
     * 插入信息
     *
     * @param cn
     */
    private void insertTable(ASTNode cn) {
        if (CollectionUtils.isEmpty(cn.getChildren())) {
            return;
        }
        for (Node child : cn.getChildren()) {
            ASTNode cc = (ASTNode) child;
            switch (cc.getToken().getType()) {
                case TOK_TABNAME:
                    String tableName = Joiner.on(".").join(cc.getChildren().stream().map(n -> ((ASTNode) n).getText()).collect(Collectors.toList()));
                    break;
                case TOK_PARTVAL:
                    break;
                default:
            }
            insertTable(cc);
        }
    }

    /**
     * 最外层列
     *
     * @param cn
     */
    private void outermostColumns(ASTNode cn) {
        if (CollectionUtils.isEmpty(cn.getChildren())) {
            return;
        }
        for (Node cnChild : cn.getChildren()) {
            ASTNode cc = (ASTNode) cnChild;
            if (cc.getToken().getType() == TOK_SELEXPR) {
                String alias = getSelExprAlias(cc);
                continue;
            }
            outermostColumns(cc);
        }
    }

    /**
     * 列别名获取
     *
     * @param cc
     * @return
     */
    private String getSelExprAlias(ASTNode cc) {
        ASTNode child = (ASTNode) cc.getChild(cc.getChildCount() - 1);
        if (child.getToken().getType() == TOK_TABLE_OR_COL || child.getToken().getType() == DOT) {
            return child.getChild(child.getChildCount() - 1).getText();
        } else {
            return child.getText();
        }
    }

    public static void main(String[] args) {
        String sql23 = "insert overwrite table dwa_jira.dwa_jira_bug_online_week_detail_p_daily\n" +
                "SELECT  CONCAT(p.pkey, '-', ji.issuenum) AS issue_key,\n" +
                "       ji.SUMMARY AS issue_summary,\n" +
                "\t   ji.CREATED AS issue_create_time, -- 创建时间\n" +
                " ji.REPORTER AS issue_reporter, -- 报告人\n" +
                " ji.ASSIGNEE AS issue_assignee, -- 经办人\n" +
                " ji_status.pname AS issue_status_name, -- 状态\n" +
                " ji_priority.pname AS issue_level_name, -- 优先级\n" +
                " cv_bug_dengji.customvalue AS bug_dengji,  -- BUG等级\n" +
                "   p.pname as  issue_group -- 所属组\n" +
                "FROM (select * from dwd_system.dwd_jira_jiraissue_f_p_daily  where data_date='#{dw.action.schedule.data.date}') ji\n" +
                "JOIN  (select * from dwd_system.dwd_jira_project_f_p_daily   where data_date='#{dw.action.schedule.data.date}' ) p ON ji.PROJECT=p.ID\n" +
                "LEFT JOIN  (select * from dwd_system.dwd_jira_issuestatus_f_p_daily  where data_date='#{dw.action.schedule.data.date}' ) ji_status ON ji_status.ID=ji.issuestatus -- issue status\n" +
                "LEFT JOIN (select * from dwd_system.dwd_jira_priority_f_p_daily  where data_date='#{dw.action.schedule.data.date}' ) ji_priority ON ji_priority.ID=ji.PRIORITY -- issue level\n" +
                "LEFT JOIN (select * from dwd_system.dwd_jira_resolution_f_p_daily  where data_date='#{dw.action.schedule.data.date}' ) ji_resolution ON ji_resolution.ID=ji.RESOLUTION -- issue resolution\n" +
                "LEFT JOIN (select * from dwd_system.dwd_jira_changegroup_f_p_daily  where data_date='#{dw.action.schedule.data.date}' AND ID in (select groupid  from dwd_system.dwd_jira_changeitem_f_p_daily  where data_date='#{dw.action.schedule.data.date}' and NEWSTRING='Approved')) ji_changegroup ON ji_changegroup.issueid=ji.ID -- 需求的响应时间\n" +
                "\n" +
                "LEFT JOIN (select * from dwd_system.dwd_jira_customfieldvalue_f_p_daily  where data_date='#{dw.action.schedule.data.date}' ) cv_bug_relate_sys ON cv_bug_relate_sys.ISSUE=ji.ID -- BUG等级\n" +
                "AND cv_bug_relate_sys.CUSTOMFIELD=10401\n" +
                "LEFT JOIN (select * from dwd_system.dwd_jira_customfieldoption_f_p_daily  where data_date='#{dw.action.schedule.data.date}' ) cv_bug_dengji ON cv_bug_relate_sys.STRINGVALUE= cv_bug_dengji.ID\n" +
                "WHERE ji.issuetype = 10600   -- issuetype 线上Bug\n" +
                "  and p.pname in ('IoT计算研发组','IoT接入研发组','基础平台研发组','G7S平台产品','支付中心','大数据平台','共享服务研发组','手机工单','设备运营系统','IoT研发组')    -- PROJECT = 产品域  12315 g7s\n";
        long start = System.currentTimeMillis();
        HiveSqlParser hiveSqlParse = new HiveSqlParser(sql23);
        long end = System.currentTimeMillis();
        System.out.printf("cost = [%s]\n",(end-start));
        for (String table : hiveSqlParse.getTables()) {
            System.out.println(table);
        }
    }
}